<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/ol.min.css"
    integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer" />
  <title>Overlay显示</title>

  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    :root {
      --top-height: 50px;
    }

    html,
    body,
    #app,
    .app-map {
      height: 100%;
      height: 100%;
    }

    .app-btns {
      position: fixed;
      right: 10px;
      top: 10px;
      background-color: #fff;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
      width: 210px;
      padding: 25px;
      text-align: center;
      border-radius: 5px;
      display: flex;
      flex-direction: column;
      z-index: 2;
    }

    .app-btns button {
      font-size: 18px;
      border: none;
      padding: 12px 20px;
      border-radius: 4px;
      color: #fff;
      background-color: #409eff;
      border-color: #409eff;
      cursor: pointer;
      border: 1px solid #dcdfe6;
      margin-bottom: 5px;
    }

    .app-btns button:hover {
      background: #66b1ff;
      border-color: #66b1ff;
    }

    .app-btns button.active {
      background-color: #07c160;
    }

    #popup {
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
      background-color: #fff;
      width: 350px;
      z-index: 13;
      border-radius: 4px;
      border: 1px solid #ebeef5;
      font-size: 16px;
    }

    #popup .top {
      height: var(--top-height);
      display: flex;
      border-bottom: 1px solid #ebeef5;
      padding-left: 20px;
    }

    #popup .top .name {
      width: calc(100% - var(--top-height));
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      line-height: var(--top-height);
    }

    #popup .top .close {
      width: var(--top-height);
      color: #606266;
      cursor: pointer;
      background-color: #fff;
      border: none;
      border-left: 1px solid #ebeef5;
      font-size: 16px;
    }

    #popup .top .close:hover {
      background-color: #eee;
      color: #66b1ff;
    }

    #popup .bot {
      padding: 0 20px;
    }

    #popup .bot li {
      height: var(--top-height);
      display: flex;
      justify-content: space-between;
    }

    #popup .bot li span {
      display: inline-block;
      line-height: var(--top-height);
      width: calc(100% - 80px);
    }

    #popup .bot li span.label {
      width: 80px;
    }
  </style>
</head>

<body>
  <div id="app">
    <div class="app-map" id="app-map"></div>
    <div class="app-btns">
      <button @click='handleClickRemoveOverlay'>删除弹框</button>
    </div>
    <div id="popup">
      <div class="top">
        <div class="name">{{clickPointInfo.name}}</div>
        <button class="close" @click='handleCloseOverlay'>
          关闭
        </button>
      </div>
      <div class="bot">
        <ul>
          <li>
            <span class="label">点位ID：</span>
            <span>{{clickPointInfo.random}}</span>
          </li>
          <li>
            <span class="label">经纬度：</span>
            <span>{{clickPointInfo.center.join(' , ')}}</span>
          </li>
        </ul>
      </div>
    </div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/dist/ol.min.js"
    integrity="sha512-+nvfloZUX7awRy1yslYBsicmHKh/qFW5w79+AiGiNcbewg0nBy7AS4G3+aK/Rm+eGPOKlO3tLuVphMxFXeKeOQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js"
    integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>

  <script>
    const { createApp } = Vue;
    // feature图片
    const base64Img = '';
    // 基础样式style
    const baseStyle = new ol.style.Style({
      image: new ol.style.Icon({
        src: base64Img,
        scale: 1.5,
        anchor: [0.5, 0.5],
        rotateWithView: true,
        rotation: 0,
        opacity: 1
      }),
    });
    // 点位信息
    const pointData = [
      {
        name: '北京市',
        center: [116.405285, 39.904989]
      },
      {
        name: '天津市',
        center: [117.190182, 39.125596]
      },
      {
        name: '河北省',
        center: [114.502461, 38.045474]
      },
      {
        name: '山西省',
        center: [112.549248, 37.857014]
      },
      {
        name: '内蒙古自治区',
        center: [111.670801, 40.818311]
      },
      {
        name: '辽宁省',
        center: [123.429096, 41.796767]
      },
      {
        name: '吉林省',
        center: [125.3245, 43.886841]
      },
      {
        name: '黑龙江省',
        center: [126.642464, 45.756967]
      },
      {
        name: '上海市',
        center: [121.472644, 31.231706]
      },
      {
        name: '江苏省',
        center: [118.767413, 32.041544]
      },
      {
        name: '浙江省',
        center: [120.153576, 30.287459]
      },
      {
        name: '安徽省',
        center: [117.283042, 31.86119]
      },
      {
        name: '福建省',
        center: [119.306239, 26.075302]
      },
      {
        name: '江西省',
        center: [115.892151, 28.676493]
      },
      {
        name: '山东省',
        center: [117.000923, 36.675807]
      },
      {
        name: '河南省',
        center: [113.665412, 34.757975]
      },
      {
        name: '湖北省',
        center: [114.298572, 30.584355]
      },
      {
        name: '湖南省',
        center: [112.982279, 28.19409]
      },
      {
        name: '广东省',
        center: [113.280637, 23.125178]
      },
      {
        name: '广西壮族自治区',
        center: [108.320004, 22.82402]
      },
      {
        name: '海南省',
        center: [110.33119, 20.031971]
      },
      {
        name: '重庆市',
        center: [106.504962, 29.533155]
      },
      {
        name: '四川省',
        center: [104.065735, 30.659462]
      },
      {
        name: '贵州省',
        center: [106.713478, 26.578343]
      },
      {
        name: '云南省',
        center: [102.712251, 25.040609]
      },
      {
        name: '西藏自治区',
        center: [91.132212, 29.660361]
      },
      {
        name: '陕西省',
        center: [108.948024, 34.263161]
      },
      {
        name: '甘肃省',
        center: [103.823557, 36.058039]
      },
      {
        name: '青海省',
        center: [101.778916, 36.623178]
      },
      {
        name: '宁夏回族自治区',
        center: [106.278179, 38.46637]
      },
      {
        name: '新疆维吾尔自治区',
        center: [87.617733, 43.792818]
      },
      {
        name: '台湾省',
        center: [121.509062, 25.044332]
      },
      {
        name: '香港特别行政区',
        center: [114.173355, 22.320048]
      },
      {
        name: '澳门特别行政区',
        center: [113.54909, 22.198951]
      },
    ]
    const vm = createApp({
      data() {
        return {
          map: {},
          overlay: null,
          clickPointInfo: {
            name: '',
            center: []
          }
        }
      },
      methods: {
        // 初始化地图
        initMap() {
          // 高德地图瓦片地址
          const vectorLayer = new ol.layer.Tile({
            source: new ol.source.XYZ({
              url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
            }),
            name: '初始化地图图层'
          });
          //  初始化地图
          this.map = new ol.Map({
            target: 'app-map',
            layers: [vectorLayer],
            view: new ol.View({
              projection: 'EPSG:3857',
              //设定中心点，因为默认坐标系为 3587，所以要将我们常用的经纬度坐标系4326 转换为 3587坐标系
              center: ol.proj.transform([111.8453154, 32.7383500], 'EPSG:4326', 'EPSG:3857'),
              zoom: 5,
            })
          });
          // 绑定地图事件
          this.bindMapEvt();
          // 渲染点位到地图上
          this.renderPoint();
          // 创建一个 Overlay
          this.overlay = new ol.Overlay({
            element: document.getElementById('popup'), // 弹出框的 HTML 元素
            positioning: 'bottom-center', // 设置定位方式，这里是底部中心
            autoPan: true, // 当overlay不在视口内的时候，移动地图，让其可见
            stopEvent: false, // 是否停止事件传播
          });
          // 将Overlay添加到地图上
          this.map.addOverlay(this.overlay);
        },
        // 绑定地图事件
        bindMapEvt() {
          // 监听鼠标点击
          this.map.on('click', (evt) => {
            // 根据点位像素位置，获取此位置的要素feature
            const feature = this.map.forEachFeatureAtPixel(evt.pixel, function (feature) {
              return feature;
            });
            if (feature) {
              // 获取要素的坐标
              const coordinates = feature.getGeometry().getCoordinates();
              // 获取要素的信息
              this.clickPointInfo = feature.get('info');
              if (this.overlay) {
                // 设置弹出框的位置为点击的位置 
                console.log(coordinates);
                this.overlay.setPosition(coordinates);
                // 显示弹出框
                this.overlay.getElement().style.display = 'block';
              } else {
                alert(`点击的是${this.clickPointInfo.name}，经纬度：${this.clickPointInfo.center.join('，')}`)
              }
            } else {
              // 如果没有点击到要素，隐藏弹出框
              this.overlay && (this.overlay.getElement().style.display = 'none');
            }
          });
          // 监听鼠标移动，移动到feature上时，鼠标变为可点击的状态
          this.map.on('pointermove', (e) => {
            // 获取像素位置
            let pixel = this.map.getEventPixel(e.originalEvent);
            // 根据点位像素位置，获取此位置的要素feature
            let feature = this.map.forEachFeatureAtPixel(pixel, (feature) => {
              return feature;
            });
            // 要素存在，并且是需要改变鼠标样式为pointer的feature，鼠标样式变为pointer，否则auto
            if (feature && feature.get('pointer')) {
              this.map.getTargetElement().style.cursor = 'pointer';
            } else {
              this.map.getTargetElement().style.cursor = 'auto';
            }
          });
        },
        // 删除Overlay
        handleClickRemoveOverlay() {
          if (this.overlay != null) {
            this.overlay.setMap(null);
            this.overlay = null;
          }
          alert('overlay已删除');
        },
        // 点击上的关闭
        handleCloseOverlay() {
          this.overlay.getElement().style.display = 'none';
        },
        // 在地图上添加点位
        renderPoint(numPoints) {
          // 根据positions创建一个新的数据源和要素数组，
          const vectorSource = new ol.source.Vector({
            features: pointData.map(e => {
              // ol.proj.fromLonLat用于将经纬度坐标从 WGS84 坐标系转换为地图投影坐标系
              const feature = new ol.Feature({
                geometry: new ol.geom.Point(ol.proj.fromLonLat(e.center)),
                info: {
                  random: Math.ceil(Math.random() * 100000),
                  ...e
                },
                pointer: true
              });
              feature.setStyle(baseStyle);
              return feature;
            })
          });
          // 创建带有数据源的矢量图层
          this.pointLayer = new ol.layer.Vector({
            source: vectorSource,
            layerID: 'addpointLayer',
            name: '点位图层1'
          });
          // 将矢量图层添加到地图上
          this.map.addLayer(this.pointLayer);
        }
      },
      mounted() {
        this.initMap();
      }
    }).mount('#app')
  </script>

</body>

</html>